home *** CD-ROM | disk | FTP | other *** search
/ ftp.mactech.com 2010 / ftp.mactech.com.tar / ftp.mactech.com / macintosh-c / macc-carbon-demos-nonbinhex.sit / macc-carbon-demos-nonbinhex / chap24-demo-carbon events / SoundAndSpeech.c < prev    next >
C/C++ Source or Header  |  2001-05-19  |  15KB  |  549 lines

  1. // *******************************************************************************************
  2. // SoundAndSpeech.c                                                         CARBON EVENT MODEL
  3. // *******************************************************************************************
  4. //
  5. // This program opens a modeless dialog containing five bevel button controls arranged in
  6. // two groups, namely, a synchronous sound group and an asynchronous sound group.  Clicking on
  7. // the bevel buttons causes sound to be played back or recorded as follows:
  8. //
  9. // •    Synchronous group:
  10. //
  11. //        •  Play sound resource.
  12. //
  13. //        •  Record sound resource (Mac OS 8/9 only).
  14. //
  15. //        •  Speak text string.
  16. //
  17. // •    Asynchronous group:
  18. //
  19. //        •  Play sound resource.
  20. //
  21. //        •  Speak text string.
  22. //
  23. // The asynchronous sound sections of the program utilise a special library called
  24. // AsyncSoundLibPPC, which must be included in the CodeWarrior project.
  25. //
  26. // The program utilises the following resources:
  27. //
  28. // •    A 'plst' resource.
  29. //
  30. // •    A 'DLOG' resource and associated 'DITL', 'dlgx', and 'dftb' resources (all purgeable).
  31. //
  32. // •    'CNTL' resources (purgeable) for the controls within the dialog.
  33. //
  34. // •    Two 'snd ' resources, one for synchronous playback (purgeable) and one for asynchronous
  35. //        playback (purgeable).
  36. //
  37. // •    Four 'cicn' resources (purgeable).  Two are used to provide an animated display which
  38. //        halts during synchronous playback and continues during asynchronous playback.  The
  39. //        remaining two are used by the bevel button controls.
  40. //
  41. // •    Two 'STR#' resources containing "speak text" strings and error message strings (all
  42. //        purgeable).
  43. //
  44. // •    'hrct' and 'hwin' resources (purgeable) for balloon help.
  45. //
  46. // •    A 'SIZE' resource with the acceptSuspendResumeEvents, canBackground, 
  47. //        doesActivateOnFGSwitch, and isHighLevelEventAware flags set.
  48. //
  49. // Each time it is invoked, the function doRecordResource creates a new 'snd' resource with a
  50. // unique ID in the resource fork of a file titled "SoundResources".
  51. //
  52. // *******************************************************************************************
  53.  
  54. // ………………………………………………………………………………………………………………………………………………………………………………………………………………………… includes
  55.  
  56. #include <Carbon.h>
  57. #include <string.h>
  58.  
  59. // …………………………………………………………………………………………………………………………………………………………………………………………………………………………… defines
  60.  
  61. #define rDialog                                    128
  62. #define  iDone                                    1
  63. #define  iPlayResourceSync            4
  64. #define  iRecordResource                5
  65. #define  iSpeakTextSync                    6
  66. #define  iPlayResourceASync            7    
  67. #define  iSpeakTextAsync                8
  68. #define rPlaySoundResourceSync    8192
  69. #define rPlaySoundResourceASync    8193
  70. #define rSpeechStrings                    128
  71. #define rErrorStrings                        129
  72. #define  eOpenDialogFail                1
  73. #define  eCannotInitialise            2
  74. #define  eGetResource                        3
  75. #define  eMemory                                4
  76. #define  eMakeFSSpec                        5
  77. #define  eWriteResource                    6
  78. #define  eNoChannelsAvailable        7
  79. #define  ePlaySound                            8
  80. #define  eSndPlay                                9        
  81. #define  eSndRecord                            10
  82. #define  eSpeakString                        11
  83. #define rColourIcon1                        128
  84. #define rColourIcon2                        129
  85. #define kMaxChannels                        8
  86. #define kOutOfChannels                    1
  87.  
  88. // …………………………………………………………………………………………………………………………………………………………………………………………………… global variables
  89.  
  90. Boolean            gRunningOnX = false;
  91. DialogRef        gDialogRef;
  92. CIconHandle    gColourIconHdl1;
  93. CIconHandle    gColourIconHdl2;
  94.  
  95. // .............................................................. AsyncSoundLib attention flag
  96.  
  97. Boolean    gCallAS_CloseChannel = false;
  98.  
  99. // …………………………………………………………………………………………………………………………………………………………………………………………… function prototypes
  100.  
  101. void            main                                    (void);
  102. void            doPreliminaries                (void);
  103. OSStatus    windowEventHandler        (EventHandlerCallRef,EventRef,void *);
  104. void            doIdle                                (void);
  105. void            doInitialiseSoundLib    (void);
  106. void            doDialogHit                        (SInt16);
  107. void             doPlayResourceSync        (void);
  108. void            doRecordResource            (void);
  109. void            doSpeakStringSync            (void);
  110. void            doPlayResourceASync        (void);
  111. void            doSpeakStringAsync        (void);
  112. void            doSetUpDialog                    (void);
  113. void            doErrorAlert                    (SInt16);
  114. void            helpTags                            (DialogRef);
  115.  
  116. // ……………………………………………………………………………………………………………………………………………………… AsyncSoundLib function prototypes
  117.  
  118. OSErr    AS_Initialise        (Boolean *,SInt16);
  119. OSErr    AS_GetChannel        (SInt32,SndChannelPtr *);
  120. OSErr    AS_PlayID                (SInt16, SInt32 *);
  121. OSErr    AS_PlayHandle        (Handle,SInt32 *);
  122. void    AS_CloseChannel    (void);
  123. void    AS_CloseDown        (void);
  124.  
  125. // ************************************************************************************** main
  126.  
  127. void main(void)
  128. {
  129.     SInt32                response;
  130.     EventTypeSpec    windowEvents[] = { { kEventClassWindow, kEventWindowClose },
  131.                                                                      { kEventClassMouse,  kEventMouseDown   } };
  132.  
  133.     // ……………………………………………………………………………………………………………………………………………………………………………………………… do preliminaries
  134.  
  135.     doPreliminaries();
  136.  
  137.     // ……………………………………………………………………………………………………………… disable Quit item in Mac OS X Application menu
  138.  
  139.     DisableMenuCommand(NULL,'quit');
  140.  
  141.      // ………………………………………………………………………………………………………………………………………………………………………………………………… install a timer
  142.   
  143.     InstallEventLoopTimer(GetCurrentEventLoop(),0,TicksToEventTime(10),
  144.                                                 NewEventLoopTimerUPP((EventLoopTimerProcPtr) doIdle),NULL,
  145.                                                 NULL);
  146.                                                 
  147.     // ……………………………………………………………………………………………………………………………………………………………………………… open and set up dialog
  148.  
  149.     if(!(gDialogRef = GetNewDialog(rDialog,NULL,(WindowRef) -1)))
  150.     {
  151.         doErrorAlert(eOpenDialogFail);
  152.         ExitToShell();
  153.     }
  154.  
  155.     SetPortDialogPort(gDialogRef);
  156.     SetDialogDefaultItem(gDialogRef,kStdOkItemIndex);
  157.  
  158.     ChangeWindowAttributes(GetDialogWindow(gDialogRef),kWindowStandardHandlerAttribute |
  159.                                                                                                           kWindowCloseBoxAttribute,
  160.                                                                                                           kWindowCollapseBoxAttribute);
  161.  
  162.     InstallWindowEventHandler(GetDialogWindow(gDialogRef),
  163.                                                         NewEventHandlerUPP((EventHandlerProcPtr) windowEventHandler),
  164.                                                         GetEventTypeCount(windowEvents),windowEvents,0,NULL);
  165.  
  166.     Gestalt(gestaltMenuMgrAttr,&response);
  167.     if(response & gestaltMenuMgrAquaLayoutMask)
  168.     {
  169.         helpTags(gDialogRef);
  170.         gRunningOnX = true;
  171.     }
  172.  
  173.     doSetUpDialog();
  174.  
  175.     // ………………………………………………………………………………………………………………………………………………………………………… initialise AsyncSoundLib
  176.  
  177.     doInitialiseSoundLib();
  178.  
  179.     // ……………………………………………………………………………………………………………………………………………………………………………………………… get colour icons
  180.  
  181.     gColourIconHdl1 = GetCIcon(rColourIcon1);
  182.     gColourIconHdl2 = GetCIcon(rColourIcon2);
  183.  
  184.     // …………………………………………………………………………………………………………………………………………………………………… run application event loop
  185.  
  186.     RunApplicationEventLoop();
  187. }
  188.  
  189. // *************************************************************************** doPreliminaries
  190.  
  191. void  doPreliminaries(void)
  192. {
  193.     MoreMasterPointers(64);
  194.     InitCursor();
  195.     FlushEvents(everyEvent,0);
  196. }
  197.  
  198. // ************************************************************************ windowEventHandler
  199.  
  200. OSStatus  windowEventHandler(EventHandlerCallRef eventHandlerCallRef,EventRef eventRef,
  201.                                                          void* userData)
  202. {
  203.     OSStatus        result = eventNotHandledErr;
  204.     UInt32            eventClass;
  205.     UInt32            eventKind;
  206.     EventRecord    eventRecord;
  207.     SInt16            itemHit;
  208.     
  209.     eventClass = GetEventClass(eventRef);
  210.     eventKind  = GetEventKind(eventRef);
  211.  
  212.     switch(eventClass)
  213.     {
  214.         case kEventClassWindow:                                                                                             // event class window
  215.             switch(eventKind)
  216.             {
  217.                 case kEventWindowClose:
  218.                     AS_CloseDown();
  219.                     QuitApplicationEventLoop();
  220.                     result = noErr;
  221.                     break;
  222.             }
  223.  
  224.         case kEventClassMouse:                                                                                                // event class mouse
  225.             ConvertEventRefToEventRecord(eventRef,&eventRecord);
  226.             switch(eventKind)
  227.             {
  228.                 case kEventMouseDown:
  229.                     if(IsDialogEvent(&eventRecord))
  230.                     {
  231.                         if(DialogSelect(&eventRecord,&gDialogRef,&itemHit))
  232.                             doDialogHit(itemHit);
  233.                         result = noErr;
  234.                     }
  235.                     break;
  236.             }
  237.             break;
  238.     }
  239.  
  240.     return result;
  241. }
  242.  
  243. // ************************************************************************************ doIdle
  244.  
  245. void  doIdle(void)
  246. {
  247.     Rect                        theRect, eraseRect;
  248.     UInt32                     finalTicks;
  249.     SInt16                    fontNum;
  250.     static Boolean    flip;
  251.  
  252.     SetRect(&theRect,262,169,294,201);
  253.     SetRect(&eraseRect,310,170,481,200);
  254.  
  255.     if(gCallAS_CloseChannel)
  256.     {
  257.         AS_CloseChannel();
  258.         GetFNum("\pGeneva",&fontNum);
  259.         TextFont(fontNum);
  260.         TextSize(10);
  261.         MoveTo(341,189);
  262.         DrawString("\pAS_CloseChannel called");
  263.         QDFlushPortBuffer(GetWindowPort(FrontWindow()),NULL);
  264.         Delay(45,&finalTicks);
  265.     }
  266.  
  267.     if(flip)
  268.         PlotCIcon(&theRect,gColourIconHdl1);
  269.     else
  270.         PlotCIcon(&theRect,gColourIconHdl2);
  271.  
  272.     flip = !flip;
  273.  
  274.     EraseRect(&eraseRect);
  275. }
  276.  
  277. // ********************************************************************** doInitialiseSoundLib
  278.  
  279. void  doInitialiseSoundLib(void)
  280. {
  281.     if(AS_Initialise(&gCallAS_CloseChannel,kMaxChannels) != noErr)
  282.     {
  283.         doErrorAlert(eCannotInitialise);
  284.         ExitToShell();
  285.     }
  286. }
  287.  
  288. // ******************************************************************************* doDialogHit
  289.  
  290. void  doDialogHit(SInt16 item)
  291. {
  292.     switch(item) 
  293.     {
  294.         case iDone:
  295.             AS_CloseDown();
  296.             QuitApplicationEventLoop();
  297.             break;
  298.  
  299.         case iPlayResourceSync:
  300.             doPlayResourceSync();
  301.             break;
  302.  
  303.         case iRecordResource:
  304.             doRecordResource();
  305.             break;
  306.  
  307.         case iSpeakTextSync:
  308.             doSpeakStringSync();
  309.             break;
  310.  
  311.         case iPlayResourceASync:
  312.             doPlayResourceASync();
  313.             break;
  314.  
  315.         case iSpeakTextAsync:
  316.             doSpeakStringAsync();
  317.             break;
  318.     }
  319. }
  320.  
  321. // ************************************************************************ doPlayResourceSync
  322.  
  323. void  doPlayResourceSync(void)
  324. {
  325.     SndListHandle    sndListHdl;
  326.     SInt16                resErr;
  327.     OSErr                    osErr;
  328.     ControlRef        controlRef;
  329.  
  330.     sndListHdl = (SndListHandle) GetResource('snd ',rPlaySoundResourceSync);
  331.     resErr = ResError();
  332.     if(resErr != noErr)
  333.         doErrorAlert(eGetResource);
  334.  
  335.     if(sndListHdl != NULL)
  336.     {
  337.         HLock((Handle) sndListHdl);
  338.         osErr = SndPlay(NULL,sndListHdl,false);
  339.         if(osErr != noErr)
  340.             doErrorAlert(eSndPlay);
  341.         HUnlock((Handle) sndListHdl);
  342.         ReleaseResource((Handle) sndListHdl);
  343.  
  344.         GetDialogItemAsControl(gDialogRef,iPlayResourceSync,&controlRef);
  345.         SetControlValue(controlRef,0);
  346.     }
  347. }
  348.  
  349. // ************************************************************************** doRecordResource
  350.  
  351. void  doRecordResource(void)
  352. {
  353.     SInt16            oldResFileRefNum, theResourceID, resErr, tempResFileRefNum;
  354.     BitMap            screenBits;
  355.     Point                topLeft;
  356.     OSErr                memErr, osErr;
  357.     Handle            soundHdl;
  358.     FSSpec            fileSpecTemp;
  359.     ControlRef    controlRef;
  360.  
  361.     oldResFileRefNum = CurResFile();
  362.  
  363.     GetQDGlobalsScreenBits(&screenBits);
  364.     topLeft.h = (screenBits.bounds.right / 2) - 156;
  365.     topLeft.v = 150;
  366.     
  367.     soundHdl = NewHandle(25000);
  368.     memErr = MemError();
  369.     if(memErr != noErr)
  370.     {
  371.         doErrorAlert(eMemory);
  372.         return;
  373.     }
  374.  
  375.     osErr = FSMakeFSSpec(0,0,"\pSoundResources",&fileSpecTemp);
  376.     if(osErr == noErr)
  377.     {
  378.         tempResFileRefNum = FSpOpenResFile(&fileSpecTemp,fsWrPerm);
  379.         UseResFile(tempResFileRefNum);
  380.     }
  381.     else
  382.         doErrorAlert(eMakeFSSpec);
  383.  
  384.     if(osErr == noErr)
  385.     {
  386.         osErr = SndRecord(NULL,topLeft,siBetterQuality,&(SndListHandle) soundHdl);
  387.         if(osErr != noErr && osErr != userCanceledErr)
  388.             doErrorAlert(eSndRecord);
  389.         else if(osErr != userCanceledErr)
  390.         {
  391.             do
  392.             {
  393.                 theResourceID = UniqueID('snd ');
  394.             } while(theResourceID <= 8191 && theResourceID >= 0);
  395.  
  396.             AddResource(soundHdl,'snd ',theResourceID,"\pTest");
  397.             resErr = ResError();
  398.             if(resErr == noErr)
  399.                 UpdateResFile(tempResFileRefNum);
  400.             resErr = ResError();
  401.             if(resErr != noErr)
  402.                 doErrorAlert(eWriteResource);
  403.         }
  404.         
  405.         CloseResFile(tempResFileRefNum);
  406.     }
  407.  
  408.     DisposeHandle(soundHdl);
  409.     UseResFile(oldResFileRefNum);
  410.  
  411.     GetDialogItemAsControl(gDialogRef,iRecordResource,&controlRef);
  412.     SetControlValue(controlRef,0);
  413. }
  414.  
  415. // ************************************************************************* doSpeakStringSync
  416.  
  417. void  doSpeakStringSync(void)
  418. {
  419.     SInt16            activeChannels;
  420.     Str255            theString;
  421.     OSErr                resErr, osErr;
  422.     ControlRef    controlRef;
  423.  
  424.     activeChannels = SpeechBusy();
  425.  
  426.     GetIndString(theString,rSpeechStrings,1);
  427.     resErr = ResError();
  428.     if(resErr != noErr)
  429.     {
  430.         doErrorAlert(eGetResource);
  431.         return;
  432.     }
  433.  
  434.     osErr = SpeakString(theString);
  435.     if(osErr != noErr)
  436.         doErrorAlert(eSpeakString);
  437.  
  438.     while(SpeechBusy() != activeChannels)
  439.         ;
  440.  
  441.     GetDialogItemAsControl(gDialogRef,iSpeakTextSync,&controlRef);
  442.     SetControlValue(controlRef,0);
  443. }
  444.  
  445. // *********************************************************************** doPlayResourceASync
  446.  
  447. void  doPlayResourceASync(void)
  448. {
  449.     SInt16    error;
  450.  
  451.     error = AS_PlayID(rPlaySoundResourceASync,NULL);
  452.     if(error == kOutOfChannels)
  453.         doErrorAlert(eNoChannelsAvailable);
  454.     else
  455.         if(error != noErr)
  456.             doErrorAlert(ePlaySound);
  457. }
  458.  
  459. // ************************************************************************ doSpeakStringAsync
  460.  
  461. void  doSpeakStringAsync(void)
  462. {
  463.     Str255    theString;
  464.     OSErr        resErr, osErr;
  465.  
  466.     GetIndString(theString,rSpeechStrings,2);
  467.     resErr = ResError();
  468.     if(resErr != noErr)
  469.     {
  470.         doErrorAlert(eGetResource);
  471.         return;
  472.     }
  473.  
  474.     osErr = SpeakString(theString);
  475.     if(osErr != noErr)
  476.         doErrorAlert(eSpeakString);
  477. }
  478.  
  479. // ***************************************************************************** doSetUpDialog
  480.  
  481. void  doSetUpDialog(void)
  482. {
  483.     SInt16                                                a;
  484.     Point                                                    offset;
  485.     ControlRef                                        controlRef;
  486.     ControlButtonGraphicAlignment    alignConstant = kControlBevelButtonAlignLeft;
  487.     ControlButtonTextPlacement        placeConstant = kControlBevelButtonPlaceToRightOfGraphic;
  488.  
  489.     offset.v = 1;
  490.     offset.h = 5;
  491.  
  492.     for(a=iPlayResourceSync;a<iSpeakTextAsync+1;a++)
  493.     {
  494.         GetDialogItemAsControl(gDialogRef,a,&controlRef);
  495.         SetControlData(controlRef,kControlEntireControl,kControlBevelButtonGraphicAlignTag,
  496.                                      sizeof(alignConstant),&alignConstant);
  497.         SetControlData(controlRef,kControlEntireControl,kControlBevelButtonGraphicOffsetTag,
  498.                                      sizeof(offset),&offset);
  499.         SetControlData(controlRef,kControlEntireControl,kControlBevelButtonTextPlaceTag,
  500.                                     sizeof(placeConstant),&placeConstant);
  501.     }
  502.  
  503.     if(gRunningOnX)
  504.     {
  505.         GetDialogItemAsControl(gDialogRef,iRecordResource,&controlRef);
  506.         DeactivateControl(controlRef);
  507.     }
  508. }
  509.  
  510. // ****************************************************************************** doErrorAlert
  511.  
  512. void  doErrorAlert(SInt16 errorStringIndex)
  513. {
  514.     Str255    errorString;
  515.     SInt16    itemHit;
  516.  
  517.     GetIndString(errorString,rErrorStrings,errorStringIndex);
  518.  
  519.     StandardAlert(kAlertCautionAlert,errorString,NULL,NULL,&itemHit);
  520. }
  521.  
  522. // ********************************************************************************** helpTags
  523.  
  524. void  helpTags(DialogRef dialogRef)
  525. {
  526.     HMHelpContentRec    helpContent;
  527.     SInt16                        a;
  528.     ControlRef                controlRef;
  529.  
  530.   memset(&helpContent,0,sizeof(helpContent));
  531.   HMSetTagDelay(500);
  532.   HMSetHelpTagsDisplayed(true);
  533.  
  534.     helpContent.version = kMacHelpVersion;
  535.     helpContent.tagSide = kHMOutsideTopCenterAligned;
  536.     helpContent.content[kHMMinimumContentIndex].contentType = kHMStringResContent;
  537.     helpContent.content[kHMMinimumContentIndex].u.tagStringRes.hmmResID = 130;
  538.  
  539.     for(a = 1;a <= 5; a++)
  540.     {
  541.         if(a == 2)
  542.             continue;
  543.         helpContent.content[kHMMinimumContentIndex].u.tagStringRes.hmmIndex = a;
  544.         GetDialogItemAsControl(dialogRef,a + 3,&controlRef);
  545.         HMSetControlHelpContent(controlRef,&helpContent);
  546.     }
  547. }
  548.  
  549. // *******************************************************************************************